---
title: "02-JVM 与运行机制"
aliases:
- "JVM 与运行机制"
created: 2025-12-23
---
# JVM 与运行机制
---
## 一、JVM、JDK、JRE 的关系
### **1.1 三者关系图**
```drawio
```
### **1.2 各组件详解**
#### **JVM(Java Virtual Machine)**
```drawio
```
##### **JVM 的多语言支持:**
```drawio
```
##### **JVM 的多种实现**:
| **JVM 实现** | **开发商** | **特点** |
| --- | --- | --- |
| **HotSpot** | Oracle/OpenJDK | 最主流,默认 JVM |
| **OpenJ9** | IBM/Eclipse | 低内存占用,快速启动 |
| **GraalVM** | Oracle | 支持多语言,AOT 编译 |
| **Azul Zing** | Azul | 超低延迟 GC |
| **Dragonwell** | Alibaba | 针对电商场景优化 |
#### **JRE(Java Runtime Environment)**
```
// JRE 核心类库示例
// java.lang - 自动导入,无需 import
String str = "Hello"; // java.lang.String
Integer num = 100; // java.lang.Integer
Thread thread = new Thread(); // java.lang.Thread
// java.util - 集合框架
import java.util.ArrayList;
import java.util.HashMap;
List list = new ArrayList<>();
Map map = new HashMap<>();
// java.io - 输入输出
import java.io.File;
import java.io.FileInputStream;
File file = new File("test.txt");
// java.net - 网络编程
import java.net.URL;
import java.net.HttpURLConnection;
URL url = new URL("https://example.com");
```
#### **JDK(Java Development Kit)**
```
# JDK 目录结构 (JDK 11+)
jdk-17/
├── bin/ # 开发工具
│ ├── java # 运行 Java 程序
│ ├── javac # 编译器
│ ├── javadoc # 文档生成
│ ├── jdb # 调试器
│ ├── jar # 打包工具
│ ├── jlink # 自定义运行时镜像
│ ├── jshell # 交互式 REPL (JDK 9+)
│ ├── jconsole # 监控工具
│ ├── jvisualvm # 可视化监控 (需单独下载)
│ └── ...
├── conf/ # 配置文件
├── include/ # C/C++ 头文件 (JNI)
├── jmods/ # 模块文件 (JDK 9+)
├── lib/ # 核心类库
│ ├── modules # 模块化类库
│ └── src.zip # 源码
└── legal/ # 许可证文件
```
```
# 常用 JDK 工具命令
# 编译 Java 文件
javac HelloWorld.java
# 运行 Java 程序
java HelloWorld
# 查看字节码
javap -c HelloWorld.class
# 生成文档
javadoc -d docs *.java
# 打包 JAR
jar cvf app.jar *.class
# 交互式 Shell (JDK 9+)
jshell
# 创建自定义运行时 (JDK 9+)
jlink --module-path $JAVA_HOME/jmods \
--add-modules java.base \
--output custom-runtime
```
### **1.3 重要变化**
```drawio
```
```
// JDK 9+ 模块化示例
// module-info.java
module com.myapp {
requires java.base; // 基础模块(默认)
requires java.sql; // 数据库模块
requires java.logging; // 日志模块
exports com.myapp.api; // 导出包供其他模块使用
}
```
---
## 二、字节码详解
### **2.1 什么是字节码**
```drawio
```
### **2.2 字节码文件结构**
```drawio
```
### **2.3 字节码实战分析**
```java
// 源代码: HelloWorld.java
public class HelloWorld {
private int count = 0;
public int add(int a, int b) {
return a + b;
}
public static void main(String[] args) {
HelloWorld hw = new HelloWorld();
int result = hw.add(1, 2);
System.out.println(result);
}
}
```
**javap反编译:**
```
# 编译
javac HelloWorld.java
# 反编译查看字节码
javap -v -p HelloWorld.class
```
**字节码输出分析**:
```
Classfile /path/to/HelloWorld.class
Last modified 2024-1-1; size 537 bytes
SHA-256 checksum abc123...
Compiled from "HelloWorld.java"
// ==================== 类信息 ====================
public class HelloWorld
minor version: 0
major version: 61 // JDK 17
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
this_class: #8 // HelloWorld
super_class: #2 // java/lang/Object
interfaces: 0, fields: 1, methods: 3, attributes: 1
// ==================== 常量池 ====================
Constant pool:
#1 = Methodref #2.#3 // java/lang/Object."":()V
#2 = Class #4 // java/lang/Object
#3 = NameAndType #5:#6 // "":()V
#4 = Utf8 java/lang/Object
#5 = Utf8
#6 = Utf8 ()V
#7 = Fieldref #8.#9 // HelloWorld.count:I
#8 = Class #10 // HelloWorld
...
// ==================== 字段定义 ====================
private int count;
descriptor: I // I 表示 int 类型
flags: (0x0002) ACC_PRIVATE
// ==================== 方法: add ====================
public int add(int, int);
descriptor: (II)I // 参数: 2个int, 返回: int
flags: (0x0001) ACC_PUBLIC
Code:
stack=2, locals=3, args_size=3 // 操作数栈深度=2, 局部变量=3
0: iload_1 // 将第1个int参数压入操作数栈
1: iload_2 // 将第2个int参数压入操作数栈
2: iadd // 弹出两个int相加,结果压栈
3: ireturn // 返回栈顶int值
LineNumberTable:
line 5: 0 // 源代码第5行对应字节码偏移0
// ==================== 方法: main ====================
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=3, args_size=1
0: new #8 // 创建 HelloWorld 对象
3: dup // 复制栈顶引用
4: invokespecial #1 // 调用构造方法
7: astore_1 // 存储到局部变量1
8: aload_1 // 加载局部变量1
9: iconst_1 // 常量1压栈
10: iconst_2 // 常量2压栈
11: invokevirtual #11 // 调用 add 方法
14: istore_2 // 存储结果到局部变量2
15: getstatic #12 // 获取 System.out
18: iload_2 // 加载结果
19: invokevirtual #18 // 调用 println
22: return // 返回
```
### **2.4 常见字节码指令**
```drawio
```
### **2.5 字节码执行过程图解**
```drawio
```
---
## 三、编译与解释并存
### **3.1 编程语言执行方式分类**
```drawio
```
### **3.2 Java 程序完整执行流程**
```drawio
```
### **3.3 为什么说 Java 是"编译与解释并存"**
```java
// 一段 Java 代码的执行过程
public class Demo {
public static void main(String[] args) {
// 循环执行 10000 次
for (int i = 0; i < 10000; i++) {
calculate(i);
}
}
public static int calculate(int n) {
return n * n + n;
}
}
```
**执行过程**:
```drawio
```
**结论**:
| **阶段** | **方式** | **语言特征** |
| --- | --- | --- |
| .java → .class | 编译 | 编译型 |
| 字节码 → 解释执行 | 解释 | 解释型 |
| 热点代码 → 机器码 | 编译 | 编译型 |
---
## 四、JIT 即时编译器
### **4.1 JIT 工作原理**
```drawio
```
### **4.2 热点探测机制**
```java
// 热点探测示例
public class HotSpotDemo {
private static int counter = 0;
// 这个方法会被识别为"热点方法"
public static int hotMethod(int n) {
return n * n;
}
public static void main(String[] args) {
// 大量调用,触发 JIT 编译
for (int i = 0; i < 100_000; i++) {
hotMethod(i);
}
// 此时 hotMethod 已被 JIT 编译为机器码
// 后续调用将直接执行机器码
long start = System.nanoTime();
for (int i = 0; i < 100_000; i++) {
hotMethod(i);
}
long end = System.nanoTime();
System.out.println("执行时间: " + (end - start) + " ns");
}
}
```
**热点探测方式**:
```drawio
```
### **4.3 JIT 优化技术**
#### **方法内联 (Method Inlining)**
```java
// 优化前
public int calculate(int x) {
return square(x) + cube(x);
}
private int square(int n) { return n * n; }
private int cube(int n) { return n * n * n; }
// JIT 优化后 (方法内联)
public int calculate(int x) {
return (x * x) + (x * x * x); // 直接展开,消除方法调用开销
}
```
#### **逃逸分析 (Escape Analysis)**
```java
// 逃逸分析示例
public class EscapeAnalysisDemo {
public int calculate() {
// point 对象未逃逸出方法
Point point = new Point(1, 2);
return point.x + point.y;
}
private class Point {
int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
}
}
// JIT 优化后 (标量替换)
public int calculate() {
// 对象被拆解为标量,直接在栈上分配
int x = 1;
int y = 2;
return x + y; // 可能进一步优化为 return 3;
}
```
```drawio
```
#### **循环优化**
```
// 循环展开 (Loop Unrolling)
// 优化前
for (int i = 0; i < 4; i++) {
arr[i] = i * 2;
}
// JIT 优化后
arr[0] = 0;
arr[1] = 2;
arr[2] = 4;
arr[3] = 6;
// 循环剥离 (Loop Peeling)
// 优化前
for (int i = 0; i < n; i++) {
if (i == 0) {
init();
}
process(i);
}
// JIT 优化后
init();
process(0);
for (int i = 1; i < n; i++) {
process(i); // 循环内不再有条件判断
}
```
### **4.4 JIT 相关 JVM 参数**
```
# 查看 JIT 编译过程
java -XX:+PrintCompilation Demo
# 输出示例:
# 时间戳 编译ID 属性 层级 方法名
176 1 n 0 java.lang.Object:: (1 bytes)
178 2 n 0 java.lang.String::hashCode (55 bytes)
180 3 b 3 Demo::hotMethod (6 bytes)
# 属性含义:
# n = native 方法
# s = synchronized 方法
# b = 阻塞编译
# ! = 有异常处理
# % = OSR 编译
# 常用 JIT 参数
-XX:+TieredCompilation # 启用分层编译(默认开启)
-XX:CompileThreshold=10000 # 编译阈值
-XX:+PrintCompilation # 打印编译信息
-XX:+UnlockDiagnosticVMOptions # 解锁诊断选项
-XX:+PrintInlining # 打印内联信息
-XX:+PrintAssembly # 打印汇编代码(需要 hsdis 插件)
```
---
## 五、AOT 提前编译
### **5.1 AOT 概述**
```drawio
```
### **5.2 JIT vs AOT 详细对比**
| **指标** | **JIT 即时编译** | **AOT 提前编译** |
| --- | --- | --- |
| **编译时机** | 运行时 | 构建时 |
| **启动速度** | 慢(需预热) | 快 |
| **峰值性能** | 高(可做运行时优化) | 中等 |
| **内存占用** | 较大 | 较小 |
| **打包体积** | 较大 | 较小 |
| **动态特性** | 完全支持 | 受限 |
| **适用场景** | 长时间运行的服务 | 云原生/Serverless |
### **5.3 为什么不全用 AOT?**
```drawio
```
```java
// 反射示例 - AOT 需要额外配置
public class ReflectionDemo {
public static void main(String[] args) throws Exception {
// 运行时动态加载类 - AOT 无法预知
Class> clazz = Class.forName("com.example.User");
Object obj = clazz.getDeclaredConstructor().newInstance();
// 动态调用方法
Method method = clazz.getMethod("getName");
String name = (String) method.invoke(obj);
}
}
// 使用 GraalVM Native Image 需要提供反射配置文件
// reflect-config.json
[
{
"name": "com.example.User",
"allDeclaredConstructors": true,
"allPublicMethods": true
}
]
```
### **5.4 GraalVM 与 Native Image**
```drawio
```
**Native Image 构建示例**:
```
# 安装 GraalVM 和 Native Image
sdk install java 21-graalce
gu install native-image
# 编译 Java 代码为原生可执行文件
native-image -jar myapp.jar myapp
# 运行原生镜像
./myapp
# 对比启动时间
# JVM 模式: java -jar myapp.jar → 约 1-3 秒
# Native 模式: ./myapp → 约 10-50 毫秒
```
**Spring Boot 3 Native 支持**:
```
org.graalvm.buildtools
native-maven-plugin
```
```
# 构建 Spring Boot Native 镜像
mvn -Pnative native:compile
# 或使用 Buildpacks
mvn spring-boot:build-image -Pnative
```
### **5.5 AOT 适用场景**
```drawio
```
---
## 六、Oracle JDK 与 OpenJDK
### **6.1 发展历史**
```drawio
```
### **6.2 主要区别对比**
```drawio
```
### **6.3 JDK 发行版生态**
```drawio
```
### **6.4 如何选择 JDK**
```drawio
```
---
## 七、总结
```drawio
```